#!/usr/bin/env node

const net = require("net");
const fs = require("fs");
const yargs = require("yargs/yargs");
const { hideBin } = require("yargs/helpers");
const { requiresArg } = require("yargs");

function tryParse(thing) {
	try {
		const index = thing.indexOf(":") + 1;
		return JSON.parse(thing.slice(index));
	} catch (error) {
		return thing;
	}
}

function prepend(string) {
	return string.length + ":" + string;
}

function stringify(obj) {
	return prepend(JSON.stringify(obj));
}

function timestamp() {
	return new Date().toISOString().split(".")[0].replace("T", " ").replaceAll(":", "-");
}

/**
 * @param {(image: string, stop: Function) => any} callback the first arg is a data url
 * @returns {function} stop function
 */
function stream(callback, { host = "localhost", port = 6000 } = {}) {
	const socket = net.connect({ host, port });

	let deviceActor = null;
	let attempted = false;
	let image_buffer = "";

	const stop = () => socket.destroy();

	socket
		.on("data", function (data) {
			const parsed = tryParse(data.toString());

			if (image_buffer !== "") {
				image_buffer += parsed;
				if (parsed.endsWith("}")) {
					const parsed = tryParse(image_buffer);
					// fs.writeFileSync(`./screenshot ${timestamp()}.png`, parsed.substring.split(",")[1], "base64");
					// console.log(parsed.substring);
					callback(parsed.substring, stop);
					image_buffer = "";
					socket.write(stringify({ type: "screenshotToDataURL", to: deviceActor }));
				}
				return;
			}

			if (typeof parsed !== "object") {
				image_buffer += parsed;
				return;
			}

			// console.log("[PARSED]: ", parsed);

			if (!deviceActor) {
				deviceActor = parsed.deviceActor;
			}
			if (deviceActor && !attempted) {
				attempted = true;
				socket.write(stringify({ type: "screenshotToDataURL", to: deviceActor }));
			}
			if (parsed.value) {
				const { length, actor } = parsed.value;
				socket.write(stringify({ type: "substring", start: 0, end: length, to: actor }));
			}
		})
		.on("connect", function () {
			socket.write(stringify({ to: "root", type: "listTabs" }));
		})
		.on("error", function () {
			console.error("An error occured!", ...arguments);
		});

	return stop;
}

module.exports = stream;

if (require.main === module) {
	const {
		prefix = "screenshot",
		host = "localhost",
		port = 6000,
		count = 1,
		folder = "screenshots",
	} = yargs(hideBin(process.argv))
		.usage(
			`usage: kaiscr.js [-h] [--host] [--port] [--prefix] [--count]\n\nTake screenshot(s) from a KaiOS/FFOS device`
		)
		.help("h")
		.alias("h", "help")
		.options({
			host: {
				description: "The host to connect to",
				requiresArg: true,
			},
			port: {
				description: "The port to connect to",
				requiresArg: true,
			},
			prefix: {
				description: "The prefix for naming files",
				requiresArg: true,
			},
			count: {
				description:
					"How many times should I take screenshot? 0 does nothing and negative values take screenshot forever",
				requiresArg: true,
			},
			folder: {
				alias: "f",
				description: "folder name to use",
				requiresArg: true,
			},
		})
		.version(false)
		.parse();

	let index = 0;
	if (0 === count) process.exit(0);
	stream(
		(dataurl, stop) => {
			index++;
			!fs.existsSync(`./${folder}/`) && fs.mkdirSync(`./${folder}`);
			fs.writeFileSync(
				`./${folder}/${prefix} ${timestamp()} ${count !== 1 ? `(${index})` : ""}.png`,
				dataurl.split(",")[1],
				"base64"
			);
			if (index === count) {
				stop();
				process.exit(0);
			}
		},
		{ host, port }
	);
}
